import ash from '@ash.ts/ash';
import { GameConfig } from '../data/GameConfig';
import { GameNode, SpaceshipNode, AsteroidCollisionNode, BulletCollisionNode } from '../data/nodes';
import { EntityCreator } from '../util/EntityCreator';

export class GameManager extends ash.System {
    private _config: GameConfig;

    private _creator: EntityCreator;

    private _games: ash.NodeList<GameNode> | null = null;

    private _spaceships: ash.NodeList<SpaceshipNode> | null = null;

    private _asteroids: ash.NodeList<AsteroidCollisionNode> | null = null;

    private _bullets: ash.NodeList<BulletCollisionNode> | null = null;

    public constructor(creator: EntityCreator, config: GameConfig) {
        super();
        this._creator = creator;
        this._config = config;
    }

    public addToEngine(engine: ash.Engine): void {
        this._games = engine.getNodeList(GameNode);
        this._spaceships = engine.getNodeList(SpaceshipNode);
        this._asteroids = engine.getNodeList(AsteroidCollisionNode);
        this._bullets = engine.getNodeList(BulletCollisionNode);
    }

    public update(time: number): void {
        const gameNode = this._games!.head;
        if (gameNode && gameNode.state.playing) {
            if (this._spaceships!.empty) {
                if (gameNode.state.lives > 0) {
                    const positionX = this._config.width / 2;
                    const positionY = this._config.height / 2;
                    let clearToAddSpaceship = true;
                    for (let asteroid = this._asteroids!.head; asteroid; asteroid = asteroid.next) {
                        const distance = Math.hypot(asteroid.position.x - positionX, asteroid.position.y - positionY);
                        if (distance <= asteroid.collision.radius + 50) {
                            clearToAddSpaceship = false;
                            break;
                        }
                    }
                    if (clearToAddSpaceship) {
                        this._creator.createSpaceship();
                    }
                } else {
                    gameNode.state.playing = false;
                    this._creator.createWaitForClick();
                }
            }

            if (this._asteroids!.empty && this._bullets!.empty && this._spaceships!.head) {
                // next level
                const spaceship: SpaceshipNode | null = this._spaceships!.head;
                gameNode.state.level += 1;
                const minAsteroids = 2;
                const asteroidCount: number = minAsteroids + gameNode.state.level;
                for (let i = 0; i < asteroidCount; i += 1) {
                    let positionX: number;
                    let positionY: number;
                    // check not on top of spaceship
                    do {
                        positionX = (Math.random() - 0.5) * this._config.width;
                        positionY = (Math.random() - 0.5) * this._config.height;
                    }
                    while (Math.hypot(positionX - spaceship.position.x, positionY - spaceship.position.y) <= 80);
                    this._creator.createAsteroid(30, positionX, positionY);
                }
            }
        }
    }

    public removeFromEngine(engine: ash.Engine): void {
        this._games = null;
        this._spaceships = null;
        this._asteroids = null;
        this._bullets = null;
    }
}
